package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.hmdp.dto.Result;
import com.hmdp.entity.Shop;
import com.hmdp.mapper.ShopMapper;
import com.hmdp.service.IShopService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 */
@Slf4j
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ShopMapper shopMapper;

    @Override
    public Result getById(Long id) {
        String tokenKey = RedisConstants.CACHE_SHOP_KEY + id;

        // 从 Redis 中查找商品
        Map<Object, Object> cachedShop = stringRedisTemplate.opsForHash().entries(tokenKey);

        // 若 Redis 中存在，直接返回
        if (!cachedShop.isEmpty()) {
            Shop shop = BeanUtil.fillBeanWithMap(cachedShop, new Shop(), false);
            log.info("Redis Hit!");
            return Result.ok(shop);
        }

        // 若 Redis 中不存在，则去 MySQL 中查询
        log.info("Redis Miss!");
        Shop shop = shopMapper.selectById(id);

        // 若 MySQL 中也不存在，则返回错误
        if (shop == null) {
            return Result.fail("Sorry, this shop is not exist!");
        }

        // 若 MySQL 中存在，则将查询到的结果加入到 Redis 中
        Map<String, Object> shopMap = BeanUtil.beanToMap(shop, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor((fieldName, fieldValue) -> {
                            if (fieldValue == null) return "";
                            return fieldValue.toString();
                        }));

        log.info("MySQL Hit!");

        stringRedisTemplate.opsForHash().putAll(tokenKey, shopMap);
        stringRedisTemplate.expire(tokenKey, RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);

        // 返回结果
        return Result.ok(shop);
    }

    @Override
    @Transactional
    public Result updateShop(Shop shop) {

        Long id = shop.getId();
        if (id == null) {
            return Result.fail("Shop Id is Empty!");
        }

        // 写入数据库，删除缓存
        updateById(shop);
        stringRedisTemplate.delete(RedisConstants.CACHE_SHOP_KEY + id);

        return Result.ok();
    }
}
